In this exercise I will be mapping the current distribution of three species of protea chafer that occur in the Western Cape, to determine if their current ranges overlap with endangered ecosystem types (using iNat and SANBI/CapeNature data). I aim to create an interactive map using mapview() that allows viewers to pan, zoom and inspect individual observations within the City of Cape Town region only, the ecosystem threat status that they occur in, as well as the name of the ecosystem the occur in.
Threatened ecosystem types sourced from SANBI/CapeNature: https://bgis.sanbi.org/SpatialDataset/Detail/611. These data map the current threat statuses for various ecosystems in the Western Cape, and the shape files will be cropped to map only the City of Cape Town area.
Species observation data sourced from iNaturalist: https://www.inaturalist.org/observations?place_id=6986&subview=map&taxon_id=423700&verifiable=any&view=species&iconic_taxa=Insecta. These data include research grade, wild observations (though some observations occur within Kirstenbosch Botanical Gardens, and thus may be considered ‘captive’). Sub-species are included in the broader species classification for ease, and the mapped distributions will be confined to the City of Cape Town area.
Shape files of ecosystem statuses were sourced from the 2016 Ecosystem Threat Status project conducted by SANBI and CapeNature (https://bgis.sanbi.org/SpatialDataset/Detail/611). A 2018 version does exist, but the shapefile is too large to use in this exercise.
library(sf) # load the sf library - this allows us to work with shape files.
## Linking to GEOS 3.13.0, GDAL 3.10.1, PROJ 9.5.1; sf_use_s2() is TRUE
library(tidyverse) # load the tidyverse library - this allows us to use all the tidyverse tools
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# read the shapefile into R
threat_eco <- st_read("data/WCBSP_Ecosystem_Threat_Status_2016/BSP_Ecosystem_Threat_Status_2016.shp")
## Reading layer `BSP_Ecosystem_Threat_Status_2016' from data source
## `C:\Users\Arwenn Kummer\Documents\GIT\GISinR\data\WCBSP_Ecosystem_Threat_Status_2016\BSP_Ecosystem_Threat_Status_2016.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 174 features and 7 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 17.75735 ymin: -34.8334 xmax: 24.22241 ymax: -30.43026
## Geodetic CRS: WGS 84
# determine the coordinate reference system
st_crs(threat_eco)
## Coordinate Reference System:
## User input: WGS 84
## wkt:
## GEOGCRS["WGS 84",
## DATUM["World Geodetic System 1984",
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["latitude",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["longitude",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## ID["EPSG",4326]]
# plot threat_eco in ggplot() to do a visual check. The `CNa1_ETS14` variable gives us the threat status of each ecosystem
ggplot() +
geom_sf(data = threat_eco, aes(fill = `CNa1_ETS14`)) +
theme_minimal()
This maps the ecosystem status for the whole of the Western Cape. We
want to only focus on the Cape Peninsula and the City of Cape Town. Thus
we will crop the map:
# check for invalid geometries before cropping
threat_eco_valid <- threat_eco[st_is_valid(threat_eco), ]
# Define the bounding box for the City of Cape Town
myextent <- st_bbox(c(xmin = 18, ymin = -34.5, xmax = 19, ymax = -33), crs = st_crs(threat_eco))
# Crop the map
threat_eco_cropped <- st_crop(threat_eco_valid, myextent)
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
There were multiple errors when trying to generate the map, stating that there were overlapping polygons, or areas sharing the same vertex. The above code works around this, but it is possible that some ecosystem information may be lost in the final map…this not ideal at all, but at least the code runs.
Three of the most common protea chafers found in the Western Cape
will be used in this distribution mapping exercise; Cape Protea Chafer
(Trichostetha capensis), Green Protea Chafer (T.
fascicularis) and Signal Protea Chafer (T. signata). These
will be read into R using a function from rinat():
get_inat_obs(), and searches will be confined to the City
of Cape Town by setting the bounds as (-34.5, 18, -33, 19). Each
species’ observations will be stored in a data frame and subsequently
converted to a shape-file for mapping.
# load the rinat() library - allows us to read data from iNaturalist directly
library(rinat)
# load observations
cpc <- get_inat_obs(taxon_name = "Trichostetha capensis",
bounds = c(-34.5, 18, -33, 19), # confined searches to the City of Cape Town
maxresults = 400)
head(cpc)
## scientific_name datetime description
## 1 Trichostetha capensis capensis 2018-10-10 08:18:00 +0200
## 2 Trichostetha capensis capensis 2024-12-10 12:22:00 +0200
## 3 Trichostetha capensis capensis 2024-12-01 10:22:52 +0200
## 4 Trichostetha capensis 2024-12-11 09:45:15 +0200
## 5 Trichostetha capensis capensis 2024-12-01 12:10:00 +0200
## 6 Trichostetha capensis 2024-10-19 11:55:27 +0200
## place_guess latitude longitude
## 1 Тейбл Маунтин, Кейптаун, Южная Африка -33.95552 18.39700
## 2 Table Mountain (Nature Reserve), Cape Town, South Africa -33.95515 18.39215
## 3 Table Mountain National Park, ZA-WC-CT, ZA-WC, ZA -34.22127 18.40226
## 4 Table Mountain National Park, Cape Town, Western Cape, ZA -34.10117 18.43614
## 5 Table Mountain (Nature Reserve), Cape Town, South Africa -34.00394 18.38284
## 6 Paarl Mountain Nature Reserve, Paarl, Western Cape, ZA -33.73462 18.94322
## tag_list common_name
## 1 Peninsula Cape Protea Chafer
## 2 Peninsula Cape Protea Chafer
## 3 Peninsula Cape Protea Chafer
## 4 Cape Protea Chafer
## 5 Peninsula Cape Protea Chafer
## 6 Cape Protea Chafer
## url
## 1 https://www.inaturalist.org/observations/262478970
## 2 https://www.inaturalist.org/observations/258090301
## 3 https://www.inaturalist.org/observations/255569176
## 4 https://www.inaturalist.org/observations/254806568
## 5 https://www.inaturalist.org/observations/254531470
## 6 https://www.inaturalist.org/observations/253325744
## image_url
## 1 https://inaturalist-open-data.s3.amazonaws.com/photos/471516246/medium.jpeg
## 2 https://inaturalist-open-data.s3.amazonaws.com/photos/463003326/medium.jpg
## 3 https://inaturalist-open-data.s3.amazonaws.com/photos/458021136/medium.jpeg
## 4 https://inaturalist-open-data.s3.amazonaws.com/photos/456491316/medium.jpg
## 5 https://inaturalist-open-data.s3.amazonaws.com/photos/455930354/medium.jpg
## 6 https://inaturalist-open-data.s3.amazonaws.com/photos/453565970/medium.jpeg
## user_login id species_guess iconic_taxon_name
## 1 alexander1951 262478970 Trichostetha capensis capensis Insecta
## 2 wetlandwanderer 258090301 Peninsula Cape Protea Chafer Insecta
## 3 lmossop 255569176 Trichostetha capensis capensis Insecta
## 4 lindalakeside 254806568 Insecta
## 5 oswaldkurten 254531470 Peninsula Cape Protea Chafer Insecta
## 6 dylan_vdmast 253325744 Cape Protea Chafer Insecta
## taxon_id num_identification_agreements num_identification_disagreements
## 1 694152 1 0
## 2 694152 2 0
## 3 694152 2 0
## 4 605066 0 0
## 5 694152 2 0
## 6 605066 0 0
## observed_on_string observed_on time_observed_at time_zone
## 1 2018/10/10 08:18 2018-10-10 2018-10-10 06:18:00 UTC Pretoria
## 2 2024/12/10 12:22 PM 2024-12-10 2024-12-10 10:22:00 UTC Pretoria
## 3 2024-12-01 10:22:52 2024-12-01 2024-12-01 08:22:52 UTC Pretoria
## 4 2024-12-11 09:45:15+02:00 2024-12-11 2024-12-11 07:45:15 UTC Pretoria
## 5 2024/12/01 12:10 PM 2024-12-01 2024-12-01 10:10:00 UTC Pretoria
## 6 2024-10-19 11:55:27+02:00 2024-10-19 2024-10-19 09:55:27 UTC Pretoria
## positional_accuracy public_positional_accuracy geoprivacy taxon_geoprivacy
## 1 244 244 NA
## 2 4 4 NA
## 3 6 6 NA
## 4 8 8 NA
## 5 5 5 NA
## 6 4 4 NA
## coordinates_obscured positioning_method positioning_device user_id
## 1 false 1417418
## 2 false 4808041
## 3 false 748780
## 4 false 1474346
## 5 false 1154120
## 6 false 3769361
## user_name created_at updated_at quality_grade
## 1 2025-02-21 05:19:53 UTC 2025-02-27 13:41:39 UTC research
## 2 2025-01-11 02:39:34 UTC 2025-01-11 04:28:09 UTC research
## 3 Leighan Mossop 2024-12-19 08:08:13 UTC 2024-12-20 15:59:48 UTC research
## 4 Linda Hibbin 2024-12-11 13:00:54 UTC 2025-01-12 19:25:51 UTC needs_id
## 5 Oswald 2024-12-08 17:59:54 UTC 2025-01-17 18:56:03 UTC research
## 6 2024-11-27 20:52:56 UTC 2024-11-28 14:16:39 UTC research
## license sound_url oauth_application_id captive_cultivated
## 1 CC-BY-NC NA NA false
## 2 CC-BY-NC NA NA false
## 3 CC-BY-NC NA 2 false
## 4 CC-BY-NC NA 3 false
## 5 CC-BY-NC NA NA false
## 6 CC-BY-NC NA 3 false
# filter for only research grade and wild observations
cpc <- cpc %>% filter(positional_accuracy<46 &
latitude<0 &
!is.na(latitude) &
captive_cultivated == "false" &
quality_grade == "research")
# check the variable class
class(cpc) # it's a data frame, and we need a shapefile
## [1] "data.frame"
# convert the data frame to a spatial object to allow mapping
cpc_sf <- st_as_sf(cpc, coords = c("longitude", "latitude"), crs = 4326)
# check the coordinate reference system and class
st_crs(cpc_sf) ; class(cpc_sf)
## Coordinate Reference System:
## User input: EPSG:4326
## wkt:
## GEOGCRS["WGS 84",
## ENSEMBLE["World Geodetic System 1984 ensemble",
## MEMBER["World Geodetic System 1984 (Transit)"],
## MEMBER["World Geodetic System 1984 (G730)"],
## MEMBER["World Geodetic System 1984 (G873)"],
## MEMBER["World Geodetic System 1984 (G1150)"],
## MEMBER["World Geodetic System 1984 (G1674)"],
## MEMBER["World Geodetic System 1984 (G1762)"],
## MEMBER["World Geodetic System 1984 (G2139)"],
## MEMBER["World Geodetic System 1984 (G2296)"],
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]],
## ENSEMBLEACCURACY[2.0]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Horizontal component of 3D system."],
## AREA["World."],
## BBOX[-90,-180,90,180]],
## ID["EPSG",4326]]
## [1] "sf" "data.frame"
# plot the shape file to check that everything works and runs
ggplot() +
geom_sf(data = cpc_sf[1]) +
theme(legend.key.width = unit(10.1, "cm"))
# load observations
gpc <- get_inat_obs(taxon_name = "Trichostetha fascicularis",
bounds = c(-34.5, 18, -33, 19), # confined searches to the City of Cape Town
maxresults = 300)
head(gpc)
## scientific_name datetime description
## 1 Trichostetha fascicularis fascicularis 2024-10-04 13:03:56 +0200
## 2 Trichostetha fascicularis fascicularis 2024-11-12 08:05:23 +0200
## 3 Trichostetha fascicularis fascicularis 2024-10-16 17:08:00 +0200
## 4 Trichostetha fascicularis fascicularis 2024-10-13 12:44:57 +0200
## 5 Trichostetha fascicularis fascicularis 2024-10-11 14:17:00 +0200
## 6 Trichostetha fascicularis 2024-09-15 12:42:23 +0200
## place_guess latitude
## 1 Western Cape, ZA -34.05064
## 2 Meadowridge, Cape Town, 7806, South Africa -34.03278
## 3 Wynberg NU (2), Cape Town, 7824, South Africa -33.99025
## 4 Nautilus Street, Betty's Bay, WC, ZA -34.36043
## 5 90 de Villiers Way, Glencairn, Cape Town, 7975, South Africa -34.15540
## 6 Table Mountain National Park, ZA-WC-CT, ZA-WC, ZA -33.99267
## longitude tag_list common_name
## 1 18.52667 Cape Green Protea Chafer
## 2 18.45004 Cape Green Protea Chafer
## 3 18.42909 Cape Green Protea Chafer
## 4 18.95556 Cape Green Protea Chafer
## 5 18.41427 Cape Green Protea Chafer
## 6 18.42698 Green Protea Chafer
## url
## 1 https://www.inaturalist.org/observations/256232032
## 2 https://www.inaturalist.org/observations/251472279
## 3 https://www.inaturalist.org/observations/247727495
## 4 https://www.inaturalist.org/observations/247093852
## 5 https://www.inaturalist.org/observations/246830608
## 6 https://www.inaturalist.org/observations/245037833
## image_url
## 1 https://static.inaturalist.org/photos/459359094/medium.jpg
## 2 https://inaturalist-open-data.s3.amazonaws.com/photos/449964134/medium.jpeg
## 3 https://inaturalist-open-data.s3.amazonaws.com/photos/442508752/medium.jpg
## 4 https://inaturalist-open-data.s3.amazonaws.com/photos/441243640/medium.jpeg
## 5 https://inaturalist-open-data.s3.amazonaws.com/photos/440722853/medium.jpeg
## 6 https://inaturalist-open-data.s3.amazonaws.com/photos/437191752/medium.jpeg
## user_login id species_guess iconic_taxon_name taxon_id
## 1 danegreen 256232032 Cape Green Protea Chafer Insecta 607308
## 2 angelamcqueen 251472279 Cape Green Protea Chafer Insecta 607308
## 3 jrgale 247727495 Cape Green Protea Chafer Insecta 607308
## 4 csrimage 247093852 Cape Green Protea Chafer Insecta 607308
## 5 debtherat 246830608 Cape Green Protea Chafer Insecta 607308
## 6 migsgreenworld 245037833 Green Protea Chafer Insecta 423694
## num_identification_agreements num_identification_disagreements
## 1 2 0
## 2 2 0
## 3 2 0
## 4 2 0
## 5 2 0
## 6 1 0
## observed_on_string observed_on time_observed_at time_zone
## 1 2024-10-04 13:03:56+02:00 2024-10-04 2024-10-04 11:03:56 UTC Pretoria
## 2 2024-11-12 08:05:23 2024-11-12 2024-11-12 06:05:23 UTC Pretoria
## 3 2024/10/16 5:08 PM 2024-10-16 2024-10-16 15:08:00 UTC Pretoria
## 4 2024-10-13 12:44:57+02:00 2024-10-13 2024-10-13 10:44:57 UTC Pretoria
## 5 2024/10/11 2:17 PM 2024-10-11 2024-10-11 12:17:00 UTC Pretoria
## 6 2024-09-15 12:42:23+02:00 2024-09-15 2024-09-15 10:42:23 UTC Pretoria
## positional_accuracy public_positional_accuracy geoprivacy taxon_geoprivacy
## 1 5 28874 obscured NA
## 2 1187 1187 NA
## 3 4 4 NA
## 4 48 48 NA
## 5 54 54 NA
## 6 9 9 NA
## coordinates_obscured positioning_method positioning_device user_id user_name
## 1 true 8845744
## 2 false gps gps 1605299
## 3 false 3762511 John Gale
## 4 false 5149013
## 5 false 852523 deb
## 6 false 4988081
## created_at updated_at quality_grade license
## 1 2024-12-26 03:22:44 UTC 2024-12-26 17:26:00 UTC research
## 2 2024-11-12 19:41:24 UTC 2024-11-13 07:03:50 UTC research CC-BY-NC
## 3 2024-10-17 06:05:00 UTC 2024-10-17 17:19:22 UTC research CC-BY-NC
## 4 2024-10-13 10:52:00 UTC 2024-10-13 13:25:42 UTC research CC-BY-NC
## 5 2024-10-11 21:09:56 UTC 2024-10-12 14:11:04 UTC research CC-BY-NC
## 6 2024-10-01 08:17:09 UTC 2024-10-15 17:50:02 UTC research CC-BY
## sound_url oauth_application_id captive_cultivated
## 1 NA 3 false
## 2 NA 2 false
## 3 NA NA false
## 4 NA 3 false
## 5 NA NA false
## 6 NA 3 false
# filter for research grade and wild observations
gpc <- gpc %>% filter(positional_accuracy<46 &
latitude<0 &
!is.na(latitude) &
captive_cultivated == "false" &
quality_grade == "research")
# check the variable class
class(gpc) # it's a data frame. We need a shape file.
## [1] "data.frame"
# convert the data frame to a spatial object
gpc_sf <- st_as_sf(gpc, coords = c("longitude", "latitude"), crs = 4326)
# check the coordinate reference system and class
st_crs(gpc_sf) ; class(gpc_sf)
## Coordinate Reference System:
## User input: EPSG:4326
## wkt:
## GEOGCRS["WGS 84",
## ENSEMBLE["World Geodetic System 1984 ensemble",
## MEMBER["World Geodetic System 1984 (Transit)"],
## MEMBER["World Geodetic System 1984 (G730)"],
## MEMBER["World Geodetic System 1984 (G873)"],
## MEMBER["World Geodetic System 1984 (G1150)"],
## MEMBER["World Geodetic System 1984 (G1674)"],
## MEMBER["World Geodetic System 1984 (G1762)"],
## MEMBER["World Geodetic System 1984 (G2139)"],
## MEMBER["World Geodetic System 1984 (G2296)"],
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]],
## ENSEMBLEACCURACY[2.0]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Horizontal component of 3D system."],
## AREA["World."],
## BBOX[-90,-180,90,180]],
## ID["EPSG",4326]]
## [1] "sf" "data.frame"
# plot the shape file to check that everything works and runs
ggplot() +
geom_sf(data = gpc_sf[1]) +
theme(legend.key.width = unit(10.1, "cm"))
# load observations
spc <- get_inat_obs(taxon_name = "Trichostetha signata",
bounds = c(-34.5, 18, -33, 19), # confined searches to the City of Cape Town
maxresults = 120)
head(spc)
## scientific_name datetime description
## 1 Trichostetha signata tibialis 2024-11-27 10:19:00 +0200
## 2 Trichostetha signata 2024-09-24 12:10:49 +0200
## 3 Trichostetha signata 2023-11-25 11:42:00 +0200
## 4 Trichostetha signata signata 2023-11-27 18:51:09 +0200
## 5 Trichostetha signata signata 2023-11-27 18:51:09 +0200
## 6 Trichostetha signata 2023-11-26 12:36:00 +0200
## place_guess latitude longitude
## 1 Overberg District Municipality, South Africa -34.16741 18.97198
## 2 Stellenbosch Municipality, South Africa -33.97647 18.89099
## 3 Overberg District Municipality, South Africa -34.33027 18.85016
## 4 Overberg, ZA-WC, ZA -34.33643 18.84035
## 5 Overberg, ZA-WC, ZA -34.33643 18.84035
## 6 Helderberg Rural, Sir Lowry's Pass, 7135, South Africa -34.18278 18.94465
## tag_list common_name
## 1 CREW HH 241127 Rockview Peninsula Signal Protea Chafer
## 2 Signal Protea Chafer
## 3 Signal Protea Chafer
## 4 Common Signal Protea Chafer
## 5 Common Signal Protea Chafer
## 6 GSB 231126 Steenbras Signal Protea Chafer
## url
## 1 https://www.inaturalist.org/observations/260726074
## 2 https://www.inaturalist.org/observations/243816266
## 3 https://www.inaturalist.org/observations/192975617
## 4 https://www.inaturalist.org/observations/192371586
## 5 https://www.inaturalist.org/observations/192368589
## 6 https://www.inaturalist.org/observations/192328847
## image_url
## 1 https://inaturalist-open-data.s3.amazonaws.com/photos/468270776/medium.jpeg
## 2 https://static.inaturalist.org/photos/434814045/medium.jpeg
## 3 https://inaturalist-open-data.s3.amazonaws.com/photos/338884563/medium.jpg
## 4 https://inaturalist-open-data.s3.amazonaws.com/photos/337687168/medium.jpeg
## 5 https://inaturalist-open-data.s3.amazonaws.com/photos/337687099/medium.jpeg
## 6 https://inaturalist-open-data.s3.amazonaws.com/photos/337604344/medium.jpg
## user_login id species_guess iconic_taxon_name
## 1 linkie 260726074 Peninsula Signal Protea Chafer Insecta
## 2 wikus_burger 243816266 Signal Protea Chafer Insecta
## 3 adele84 192975617 Signal Protea Chafer Insecta
## 4 adele84 192371586 Common Signal Protea Chafer Insecta
## 5 adele84 192368589 Common Signal Protea Chafer Insecta
## 6 carinalochner 192328847 Signal Protea Chafer Insecta
## taxon_id num_identification_agreements num_identification_disagreements
## 1 694164 1 0
## 2 633155 1 0
## 3 633155 3 1
## 4 694163 3 0
## 5 694163 3 0
## 6 633155 2 0
## observed_on_string observed_on time_observed_at time_zone
## 1 2024/11/27 10:19 AM 2024-11-27 2024-11-27 08:19:00 UTC Pretoria
## 2 2024-09-24 12:10:49 2024-09-24 2024-09-24 10:10:49 UTC Pretoria
## 3 2023/11/25 11:42 AM 2023-11-25 2023-11-25 09:42:00 UTC Pretoria
## 4 2023-11-27 18:51:09 2023-11-27 2023-11-27 16:51:09 UTC Pretoria
## 5 2023-11-27 18:51:09 2023-11-27 2023-11-27 16:51:09 UTC Pretoria
## 6 2023/11/26 12:36 PM 2023-11-26 2023-11-26 10:36:00 UTC Pretoria
## positional_accuracy public_positional_accuracy geoprivacy taxon_geoprivacy
## 1 8 8 NA NA
## 2 NA NA NA NA
## 3 3 3 NA NA
## 4 4 4 NA NA
## 5 4 4 NA NA
## 6 8 8 NA NA
## coordinates_obscured positioning_method positioning_device user_id
## 1 false 681342
## 2 false 4569056
## 3 false 4939503
## 4 false 4939503
## 5 false 4939503
## 6 false 724582
## user_name created_at updated_at
## 1 2025-02-05 18:01:51 UTC 2025-02-06 07:46:12 UTC
## 2 Wikus Burger 2024-09-24 16:31:03 UTC 2024-09-25 05:47:57 UTC
## 3 Adele Scheepers Lamprecht 2023-12-03 22:43:01 UTC 2024-04-18 20:56:52 UTC
## 4 Adele Scheepers Lamprecht 2023-11-27 20:06:57 UTC 2023-12-03 23:19:33 UTC
## 5 Adele Scheepers Lamprecht 2023-11-27 19:40:06 UTC 2024-01-07 14:47:47 UTC
## 6 Carina Lochner 2023-11-27 12:38:41 UTC 2023-12-02 06:53:12 UTC
## quality_grade license sound_url oauth_application_id captive_cultivated
## 1 research CC-BY-NC NA NA false
## 2 research NA 2 false
## 3 research CC-BY NA NA false
## 4 research CC-BY NA 2 false
## 5 research CC-BY NA 2 false
## 6 research CC-BY-NC NA NA false
# select only research grade and wild observations
spc <- spc %>% filter(positional_accuracy<46 &
latitude<0 &
!is.na(latitude) &
captive_cultivated == "false" &
quality_grade == "research")
# check the variable class
class(spc) # it's a data frame and we need a shape file
## [1] "data.frame"
# convert the data frame to a spatial object
spc_sf <- st_as_sf(spc, coords = c("longitude", "latitude"), crs = 4326)
# check the coordinate reference system and class
st_crs(spc_sf) ; class(spc_sf)
## Coordinate Reference System:
## User input: EPSG:4326
## wkt:
## GEOGCRS["WGS 84",
## ENSEMBLE["World Geodetic System 1984 ensemble",
## MEMBER["World Geodetic System 1984 (Transit)"],
## MEMBER["World Geodetic System 1984 (G730)"],
## MEMBER["World Geodetic System 1984 (G873)"],
## MEMBER["World Geodetic System 1984 (G1150)"],
## MEMBER["World Geodetic System 1984 (G1674)"],
## MEMBER["World Geodetic System 1984 (G1762)"],
## MEMBER["World Geodetic System 1984 (G2139)"],
## MEMBER["World Geodetic System 1984 (G2296)"],
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]],
## ENSEMBLEACCURACY[2.0]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Horizontal component of 3D system."],
## AREA["World."],
## BBOX[-90,-180,90,180]],
## ID["EPSG",4326]]
## [1] "sf" "data.frame"
# plot the shape file to check that everything works and runs
ggplot() +
geom_sf(data = spc_sf[1]) +
theme(legend.key.width = unit(10.1, "cm"))
There are multiple subspecies for each of the above species. For simplicity, these subspecies observations have been included within the mapping of the main species. i.e. there is no differentiation between subspecies of the same species within this mapping exercise.
Fortunately, all of the shape file coordinate reference systems are WGS84 - World Geodesic System 1984. This means we don’t need to transform any of the layers before we can overlap them. We can also see from generating the above plots, that the data for threatened ecosystems and each of the species plots appropriately on coordinate axes. Now we can start layering them and working on an interactive map.
First, we’ll create a static map that shows the ecosystem
threat-status, with the beetles distribution shape files overlaid. We’ll
do this using ggplot() for now.
# Let's make the map a bit prettier: plotting the ecosystem threat status with a different colour scheme and correcting the legend title.
ggplot() +
geom_sf(data = threat_eco_cropped, aes(fill = `CNa1_ETS14`)) +
scale_fill_manual(values = c("#ffac27", "#e7815d", "#ce5693", "#b62bc9", "#9d00ff")) +
labs(fill = "Ecosystem threat status") +
theme_minimal()
Now, I scoured Google and Stackexchange trying to find out how to add a legend for the beetles but couldn’t find a solution that ran and generated a legend. As such the legend is here in plain text: T. capensis = pink. T. fascicularis = green. T. signata = turquoise.
# Overlap the beetles' distributions
ggplot() +
geom_sf(data = threat_eco_cropped, aes(fill = `CNa1_ETS14`)) +
scale_fill_manual(values = c("#ffac27", "#e7815d", "#ce5693", "#b62bc9", "#9d00ff")) +
labs(fill = "Ecosystem threat status") +
geom_sf(data = cpc_sf, color = "pink", size =0.8) +
geom_sf(data = gpc_sf, color = "green", size = 0.8) +
geom_sf(data = spc_sf, color = "turquoise", size = 0.8) +
theme_minimal()
This generates a good static map, and provides us with a broad scale view of the species distributions across the various ecosystems. But what if we want to be able to look closer and see exactly where these species occur, and in what ecosystem type? To achieve this, we will generate an interactive map using this same data.
library(mapview) # allows us to create an interactive map
library(RColorBrewer) # loads in a palette of colour schemes
mapview(threat_eco_cropped, zcol = c("CNa1_ETS14"), col.regions = brewer.pal(5,"RdYlBu"), map.types = "CartoDB.Positron", layer.name = c("Ecosystem Threat Status")) +
mapview(threat_eco_cropped, zcol = c("NAME"), layer.name = c("Ecosystem name"), hide = TRUE) +
mapview(cpc_sf, col.regions = "hotpink", layer.name = c("Trichostetha capensis")) +
mapview(gpc_sf, col.regions = "green", layer.name = c("Trichostetha fascicularis")) +
mapview(spc_sf, col.regions = "turquoise", layer.name = c("Trichostetha signata"))